// 1.迷你区块链--woniu-chain
// 2.区块链的生成,新增,校验
// 3.交易
// 4.非对称加密
// 5.挖矿
// 6.p2p网络
const initBlock = {  //创始区块
    index: 0,
    data: ' 哈哈哈',
    timestamp: 15536622963141,
    nonce: 17271,
    hash:
        '0000cba9a01e031ebac5468e033b39d691660f4725b6cea8fc362340b0d3bfd3',
    prevHash:
        '0'
}
const crypto = require('crypto')  //node.js自带加密库
class Blockchain {
    constructor() {
        this.blockchain = [
            initBlock
        ]
        this.data = []
        this.difficulity = 4 //区块计算难度
    }

    //获取最新区块
    getLastBlock() {
        return this.blockchain[this.blockchain.length - 1]
    }

    //签名校验
    transfer(from,to,amount){
        if(!from!=='0'){
            //交易非挖矿
            const blance=this.blance(from)
            if(blance<amount){
                console.log('not enough blance',from,blance,amount)
                return
            }
        }

        const trasnObj={from,to,amount}
        this.data.push(trasnObj)
        return trasnObj
    }

    //查看余额
    blance(address){
        let blance=0
        this.blockchain.forEach(block=>{
            if(!Array.isArray(block.data)){
                return //创始区块
            }
            block.data.forEach(trans=>{
                if(address==trans.from){
                    blance-=trans.amount
                }
                if(address==trans.to){
                    blance+=trans.amount
                }
            })
        })
        return blance
    }


    //挖矿
    mine(address) {

        //挖矿结束 矿工奖励,每次挖矿成功给100
        this.transfer('0',address,100)

        const newBlock = this.generateNewBlock()
        //区块合法,并且区块链和方法 就新增一下
        if (this.isValidaBlock(newBlock)&&this.isValidChain()) {
            this.blockchain.push(newBlock)
            this.data=[]
            return newBlock
        } else {
            console.log('error,invalid Block', newBlock)
        }
        return
    }

    //生成新区块
    generateNewBlock() {
        //1.生成新区块 一页新的记账加入了区块链
        //2.不停的算哈希 直到计算出符合条件的哈希值,获得记账权
        let nonce = 0
        const index = this.blockchain.length //区块索引值
        const data = this.data
        const prevHash = this.getLastBlock().hash
        let timestamp = new Date().getTime()
        let hash = this.computeHash(index, prevHash, timestamp, data, nonce)
        while (hash.slice(0, this.difficulity) !== '0'.repeat(this.difficulity)) {   //slice 方法可从已有的数组中返回选定的元素
            nonce += 1
            hash = this.computeHash(index, prevHash, timestamp, data, nonce)
        }
        return {
            index,
            data,
            prevHash,
            timestamp,
            nonce,
            hash
        }
    }

    //计算哈希
    computeHash(index, prevHash, timestamp, data, nonce) {
        //index:索引
        //timestamp:时间戳
        //data: 区块的具体信息 主要是交易信息
        //hash:当前区块信息的哈希
        //prevHash:上一个区块的哈希
        //nonce: 随机数
        return crypto
            .createHash('sha256')
            .update(index + prevHash + timestamp + data + nonce)
            .digest('hex') //转换成想要的形式


    }

    //校验区块
    isValidaBlock(newBlock, lastBlock = this.getLastBlock()) {
        if (newBlock.index !== lastBlock.index + 1) {
            return false
        } else if (newBlock.prevHash !== lastBlock.hash) {
            return false
        } else if (newBlock.hash.slice(0, this.difficulity) !== '0'.repeat(this.difficulity)) {
            return false
        }
        return true
    }

    //校验区块链
    isValidChain(chain = this.blockchain) {
        for (let i = chain.length-1; i >= 1; i--) {
            if (!this.isValidaBlock(chain[i], chain[i - 1])) {
                return false
            }
        }
        if (JSON.stringify(chain[0]) !== JSON.stringify(initBlock)) {
            return false
        }
        return true
    }
}

module.exports=Blockchain